/*
 * Copyright 2021 Huawei Technologies Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package org.edgegallery.thirdsystem.plugins;

import javax.annotation.PreDestroy;
import org.pf4j.PluginManager;
import org.pf4j.spring.SpringPluginManager;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping;

@Configuration
public class PluginConfig implements BeanFactoryAware {

    private final SpringPluginManager pluginManager;

    private final ApplicationContext applicationContext;

    private BeanFactory beanFactory;

    /**
     * PluginConfig.
     *
     * @param pm SpringPluginManager
     * @param applicationContext ApplicationContext
     */
    @Autowired
    public PluginConfig(SpringPluginManager pm, ApplicationContext applicationContext) {
        this.pluginManager = pm;
        this.applicationContext = applicationContext;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    /**
     * pluginEndpoints.
     *
     * @param pm PluginManager
     * @return message
     */
    @Bean
    @DependsOn("pluginManager")
    public String pluginEndpoints(PluginManager pm) {
        registerMvcEndpoints(pm);
        return "Success register plugin endpoints.";
    }

    private void registerMvcEndpoints(PluginManager pm) {
        pm.getExtensions(PluginInterface.class).stream().flatMap(g -> g.mvcControllers().stream())
            .forEach(r -> ((ConfigurableBeanFactory) beanFactory).registerSingleton(r.getClass().getName(), r));
        applicationContext.getBeansOfType(RequestMappingHandlerMapping.class).forEach((k, v) -> v.afterPropertiesSet());
    }

    @PreDestroy
    public void cleanup() {
        pluginManager.stopPlugins();
    }

}